﻿// --------------
// 作者:Vitity
// --------------

using System.Collections.Concurrent;

namespace NICWebApi.Extensions.DynamicAPI.Conventions;

/// <summary>
/// 控制器模型约定类，用于为控制器和动作方法添加自定义特性
/// </summary>
public class ControllerModelConvention : IControllerModelConvention, IOrderedFilter // 定义一个控制器模型约定类，实现IControllerModelConvention接口
{
    // 缓存方法特性检查结果，提高性能
    private static readonly ConcurrentDictionary<MethodInfo, bool> _dynamicApiAttributeCache = new();
    private static readonly ConcurrentDictionary<MethodInfo, bool> _notDynamicApiAttributeCache = new();

    /// <summary>
    /// 获取或设置当前约定的优先级
    /// </summary>
    public int Order { get; }

    /// <summary>
    /// 控制器模型约定
    /// </summary>
    /// <param name="controller"></param>
    public void Apply(ControllerModel controller) // 实现Apply方法，用于对控制器模型进行自定义处理
    {
        // 检查控制器类型是否定义了DynamicApiAttribute特性，或者控制器类型是否实现了IDynamicAPI接口
        if (Utils.IsController(controller.ControllerType))
        {
            // 遍历控制器中的所有动作方法
            foreach (var action in controller.Actions)
            {
                // 判断是否需要为动作方法添加自定义特性
                if (ShouldAddCustomAttribute(action))
                {
                    // 如果动作方法未定义DynamicApiAttribute特性，则添加该特性
                    if (!HasDynamicApiAttribute(action.ActionMethod))
                    {
                        action.Filters.Add(new DynamicApiAttribute());
                    }

                    var attr = action.ActionMethod.GetCustomAttribute<ApiSettingAttribute>(true) ?? 
                               controller.ControllerType.GetCustomAttribute<ApiSettingAttribute>(true);

                    if (attr != null)
                    {
                        var groups = (attr.Groups == null || attr.Groups.Length == 0) ? 
                                     new[] { Utils.DefaultGroupName } : attr.Groups;
                        
                        Utils.ActionDict[action.ActionMethod] = new Utils.ActionMeta
                        {
                            Controller = controller.ControllerName,
                            Action = action.ActionName,
                            Order = attr.Order,
                            Groups = groups,
                            DisplayName = attr.DisplayName,
                            Description = attr.Description
                        };
                    }
                }
                else
                {
                    // 如果动作方法已经定义了NotDynamicApiAttribute特性，则移除DynamicApiAttribute特性
                    if (HasNotDynamicApiAttribute(action.ActionMethod))
                    {
                        action.Filters.Remove(new DynamicApiAttribute());
                    }
                }
            }
        }
    }

    // 判断是否需要为动作方法添加自定义特性
    private bool ShouldAddCustomAttribute(ActionModel action)
    {
        // 如果动作方法已经定义了DynamicApiAttribute特性，则返回false，不需要再添加
        if (HasDynamicApiAttribute(action.ActionMethod))
            return false;
        
        // 如果动作方法已经定义了NotDynamicApiAttribute特性，则返回false，不需要再添加
        if (HasNotDynamicApiAttribute(action.ActionMethod))
            return false;
        
        // 根据业务逻辑判断是否需要添加特性，这里直接返回true，表示需要添加
        return true;
    }

    // 使用缓存检查方法是否有DynamicApiAttribute特性
    private bool HasDynamicApiAttribute(MethodInfo methodInfo)
    {
        return _dynamicApiAttributeCache.GetOrAdd(methodInfo, m => 
            m.GetCustomAttributes(typeof(DynamicApiAttribute), true).Length > 0);
    }

    // 使用缓存检查方法是否有NotDynamicApiAttribute特性
    private bool HasNotDynamicApiAttribute(MethodInfo methodInfo)
    {
        return _notDynamicApiAttributeCache.GetOrAdd(methodInfo, m => 
            m.GetCustomAttributes(typeof(NotDynamicApiAttribute), true).Length > 0);
    }
}